package sep.einfuehrung;

import java.io.File;

import com.googlecode.javacv.FFmpegFrameGrabber;
import com.googlecode.javacv.FrameGrabber;
import com.googlecode.javacv.FrameGrabber.Exception;
import com.googlecode.javacv.OpenCVFrameGrabber;

/**
 * Model for the video player
 */
public class VideoplayerModel {

	private double mThreshold1 = 10.0;
	private double mThreshold2 = 100.0;
	private int mAperatureSize = 3;
	private VideoPanel mVideopanel;
	private VideoplayerThread mThread;
	private VideoplayerListener mListener;

	/**
	 * Creates the model
	 * 
	 * @param panel
	 *            The panel which draws the images
	 */
	public VideoplayerModel(VideoPanel panel) {
		if (panel == null)
			throw new IllegalArgumentException("VideoPanel must not be null.");

		mVideopanel = panel;
	}

	/**
	 * Stops the rendering thread
	 */
	public void quit() {
		// Quit filter thread
		if (mThread != null) {
			mThread.cancel();
			
			while(mThread.isAlive());
				
			mThread = null;
		}
	}

	/**
	 * Opens a video file and starts the rendering thread
	 * 
	 * @param file
	 *            The video file to be played
	 * @return {@code true} if successful
	 */
	public boolean openFile(File file) {
		if (file == null)
			throw new IllegalArgumentException("File must not be null.");

		return openVideo(new FFmpegFrameGrabber(file));
	}

	private boolean openVideo(FrameGrabber grabber) {
		// Quit filter thread first
		quit();

		try {
			// Try to start grabbing, throws exception if video is not supported
			grabber.start();

			// Setup the filter thread and start it
			mThread = new VideoplayerThread(mVideopanel, grabber);
			mThread.setThreshold1(mThreshold1);
			mThread.setThreshold2(mThreshold2);
			mThread.setAperatureSize(mAperatureSize);
			mThread.addListener(mListener);
			mThread.start();
		} catch (Exception e) {
			return false;
		}

		return true;
	}

	/**
	 * Opens video from a camera and starts the rendering thread
	 * 
	 * @return {@code true} if successful
	 */
	public boolean openCamera() {
		return openVideo(new OpenCVFrameGrabber(0));
	}

	/**
	 * Start playback
	 */
	public void play() {
		if (mThread == null)
			throw new VideoplayerException(VideoplayerException.NO_FILE);

		mThread.play();
	}

	/**
	 * Pause playback
	 */
	public void pause() {
		if (mThread == null)
			throw new VideoplayerException(VideoplayerException.NO_FILE);

		mThread.pause();
	}

	/**
	 * Stop playback
	 */
	public void stop() {
		if (mThread == null)
			throw new VideoplayerException(VideoplayerException.NO_FILE);

		mThread.stopPlayback();
	}

	/**
	 * Set the threshold1 parameter for the canny edge filter
	 * 
	 * @param val
	 *            threshold1 value
	 */
	public void setThreshold1(double val) {
		mThreshold1 = val;

		if (mThread != null)
			mThread.setThreshold1(val);
	}

	/**
	 * Set the threshold2 parameter for the canny edge filter
	 * 
	 * @param val
	 *            threshold2 value
	 */
	public void setThreshold2(double val) {
		mThreshold2 = val;

		if (mThread != null)
			mThread.setThreshold2(val);
	}

	/**
	 * Set the aperature size for the canny edge filter
	 * 
	 * @param size
	 *            aperature size
	 */
	public void setAperatureSize(int size) {
		if (!(size == 3 || size == 5 || size == 7))
			throw new IllegalArgumentException(
					"Aperature size must be one of [3,5,7].");

		mAperatureSize = size;

		if (mThread != null)
			mThread.setAperatureSize(size);
	}

	/**
	 * Add event listener for the rendering thread
	 * 
	 * @param listener
	 *            Event listener
	 */
	public void addListener(VideoplayerListener listener) {
		mListener = listener;

		if (mThread != null)
			mThread.addListener(listener);
	}
}
